﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml.Linq;
using VisualRibbonEditor;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace VisualRibbonEditor
{
	public partial class GroupDetails : UserControl
	{
		private XElement _sourceElement;

		private bool _isEditable;

		public GroupDetails()
		{
			InitializeComponent();
		}

		public GroupDetails(XElement element)
		{
			InitializeComponent();
			this._sourceElement = element;

			this.IdTextBox.Text = element.AttributeValue("Id");

			//disable editing for system buttons
			this._isEditable = Helpers.IsGroupEditable(element.AttributeValue("Id"));

			// load languages
			foreach (string lang in MainWindow.CurrentSolution.ProvisionedLanguages)
			{
				int lcid;
				if (!Int32.TryParse(lang, out lcid)) continue;

				CultureInfo cultureInfo = CultureInfo.GetCultureInfo(lcid);
				string languageName = String.Format("[{0}] {1}{2}", lang, cultureInfo.NativeName, (lcid == 1033 ? String.Empty : " - " + cultureInfo.EnglishName));
				ComboBoxItem item = new ComboBoxItem() { Content = languageName, Tag = lang };
				LanguageId.Items.Add(item);
				if (_isEditable)
				{
					if (lang == Connection.CurrentConnection.LastLanguageUsed) LanguageId.SelectedItem = item;
					if (lang == Connection.CurrentConnection.BaseLanguage) item.FontWeight = FontWeights.Bold;
				}
				else
				{
					if (lang == Connection.CurrentConnection.BaseLanguage) LanguageId.SelectedItem = item;
				}
			}

			LoadLabel(element, "Title", LabelTextBox);
			LoadLabel(element, "Description", TooltipTextBox);
			this.PositionTextBox.Text = element.AttributeValue("Sequence");

			LoadTemplateList();

			this.Image32TextBox.Text = element.AttributeValue("Image32by32Popup");

			if (!_isEditable)
			{
				//make the control read-only.
				this.ReadOnlyButtonWarining.Visibility = System.Windows.Visibility.Visible;
				this.LanguageId.IsReadOnly = true;
				this.LanguageId.IsEnabled = false;
				this.LabelTextBox.IsReadOnly = true;
				this.TooltipTextBox.IsReadOnly = true;
				this.PositionTextBox.IsReadOnly = true;
				this.MoveLeft.Visibility = System.Windows.Visibility.Collapsed;
				this.MoveRight.Visibility = System.Windows.Visibility.Collapsed;

				//replace the autocomplete boxes with readonly textboxes (autocomplete boxes cant be made readonly)
				this.Image32TextBox.Visibility = System.Windows.Visibility.Collapsed;
				this.Image32TextBoxReadOnly.Visibility = System.Windows.Visibility.Visible;
				this.Image32TextBoxReadOnly.Text = this.Image32TextBox.Text;
				this.BrowseForImage32.Visibility = Visibility.Collapsed;
			}
			else
			{

				WebResourceManager.SetupImageAutoComplete(new AutoCompleteBox[] { Image32TextBox });

				SetupEnterKeyHandler(LabelTextBox, LabelTextBox_LostFocus);
				SetupEnterKeyHandler(TooltipTextBox, TooltipTextBox_LostFocus);
				SetupEnterKeyHandler(PositionTextBox, PositionTextBox_LostFocus);
				SetupEnterKeyHandler(Image32TextBox, Image32TextBox_LostFocus);
			}
		}

		//Templates:

		private void LoadTemplateList()
		{
			if (_isEditable)
			{
				foreach (XElement groupTemplate in _sourceElement.Ancestors().Last().Descendants("GroupTemplate"))
				{
					string groupTemplateId = groupTemplate.AttributeValue("Id");

					ComboBoxItem cbi = new ComboBoxItem();
					cbi.Tag = groupTemplateId;
					cbi.Content = groupTemplateId;

					if (_sourceElement.AttributeValue("Template") == groupTemplateId)
					{
						cbi.IsSelected = true;
					}

					TemplatePicker.Items.Add(cbi);
				}
				TemplatePicker.IsEnabled = true;
				TemplatePicker.SelectionChanged += new SelectionChangedEventHandler(TemplatePicker_SelectionChanged);
			}
			else
			{
				TemplatePicker.Items.Add(_sourceElement.AttributeValue("Template"));
				TemplatePicker.SelectedIndex = 0;
				TemplatePicker.IsEnabled = false;
			}
		}


		private void TemplatePicker_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			ComboBoxItem cbi = (ComboBoxItem) TemplatePicker.SelectedItem;
			string newTemplateId = cbi.Tag.ToString();

			if( newTemplateId != _sourceElement.AttributeValue("Template"))
			{
				_sourceElement.SetAttributeValue("Template", newTemplateId);
				GetDiffGroup().SetAttributeValue("Template", newTemplateId);

				//delete all the scales from both baseXML and diffXML.
				Deleter.DeleteGroupScales(_sourceElement);

				string[] layoutNames = GetLayoutNamesFromTemplate(newTemplateId);
				AddScales(layoutNames);

				MainWindow.CurrentMainPage.RenderRibbon();

				//templatePreview1.Render(_sourceElement.Ancestors().Last(), newTemplateId, layoutNames[0]);
			}
		}

		/// <summary>
		/// Retrieves up to two layout names from a template.
		/// (if the template has a popup layout then the popup is used to determine which
		/// layout should be the maxsize (i.e., whichever layout the popup references)
		/// and then both the maxsize and the popup layouts are returned.
		/// </summary>
		private string[] GetLayoutNamesFromTemplate(string templateId)
		{
			XElement groupTemplate = _sourceElement.Ancestors().Last()
				.Descendants("GroupTemplate")
				.Where(x => x.AttributeValue("Id") == templateId).FirstOrDefault();

			XElement popupLayout = groupTemplate.Elements("Layout").Where(x => x.AttributeValue("Title") == "Popup").FirstOrDefault();
			if (popupLayout != null)
			{
				//use the the popup layout and the layout that the popup references.
				string referencedLayout = popupLayout.AttributeValue("LayoutTitle");
				string[] layouts = new string[] { referencedLayout, "Popup" };
				return layouts;
			}
			else
			{
				//if there isnt a popup layout, then use the first and last layouts
				if (groupTemplate.Elements("Layout").Count() >= 2)
				{
					string firstLayoutName = groupTemplate.Elements("Layout").First().AttributeValue("Title");
					string lastLayoutName = groupTemplate.Elements("Layout").Last().AttributeValue("Title");
					string[] layouts = new string[] { firstLayoutName, lastLayoutName };
					return layouts;
				}
				else
				{
					//use the only layout
					string firstLayoutName = groupTemplate.Elements("Layout").First().AttributeValue("Title");
					return new string[] { firstLayoutName };
				}
			}
		}

		/// <summary>
		/// Adds the given layouts to the Scaling section of the baseXml
		/// (and adds customActions for them to the DIffXml)
		/// </summary>
		private void AddScales(string[] layouts)
		{
			XElement scaling = _sourceElement.Ancestors("Tab").First().Element("Scaling");

			//add all the layouts to the scaling section
			for (int i = 0; i < layouts.Length; i++)
			{
				//first one is a maxSize, all the rest are scales.
				string elementName = (i == 0) ? "MaxSize" : "Scale";
				string sequence = (i == 0) ? "10" : "300";
				string idSuffix = (i == 0) ? ".MaxSize" : ".Scale." + layouts[i];

				//add the scale (or maxsize) to the baseXML
				XElement el = new XElement(elementName);
				el.SetAttributeValue("Id", _sourceElement.AttributeValue("Id") + idSuffix);
				el.SetAttributeValue("GroupId", _sourceElement.AttributeValue("Id"));
				el.SetAttributeValue("Sequence", sequence);
				el.SetAttributeValue("Size", layouts[i]);
				scaling.Add(el);

				//add the scale to the customActions in the DiffXML
				Helpers.AddCustomActionToDiffXml(el);

				// <MaxSize Id="Mscrm.DashboardTab.Management.MaxSize" GroupId="Mscrm.DashboardTab.Management" Sequence="20" Size="LargeLarge" />


			}
		}



		#region Labels

		private void LabelTextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			if (_isEditable)
			{
				SaveLabel(LabelTextBox, new string[] { "Title" });
			}
		}

		private void TooltipTextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			if (_isEditable)
			{
				SaveLabel(TooltipTextBox, new string[] { "Description" });
			}
		}

		private string GetSelectedLanguage()
		{
			if (LanguageId.SelectedItem == null) return Connection.CurrentConnection.BaseLanguage;

			ComboBoxItem lang = (ComboBoxItem)LanguageId.SelectedItem;
			return lang.Tag.ToString();
		}

		private void LoadLabel(XElement buttonElement, string attributeName, TextBox tb)
		{
			string language = GetSelectedLanguage();
			string value = buttonElement.AttributeValue(attributeName) ?? string.Empty;

			if (value.StartsWith("$LocLabels:"))
			{
				string id = value.Replace("$LocLabels:", "");
				tb.Text = Helpers.GetLocLabelTextById(id, language);
			}
			else
			{
				tb.Text = value;
			}
		}

		private void SaveLabel(TextBox tb, string[] attributes)
		{
			SaveLabel(tb, attributes, GetSelectedLanguage());
		}
		private void SaveLabel(TextBox tb, string[] attributes, string language)
		{
			string newText = tb.Text;
			if (newText.StartsWith("$Resources:") || newText.StartsWith("$Resources(EntityDisplayName):"))
			{
				foreach (string att in attributes)
				{
					_sourceElement.SetAttributeValue(att, newText);
				}
			}
			else
			{
				foreach (string att in attributes)
				{
					string id = _sourceElement.AttributeValue(att);
					if (id.StartsWith("$LocLabels:"))
					{
						id = id.Replace("$LocLabels:", "");
						Helpers.SetLocLabelTextById(id, language, newText);
					}
					else
					{
						MessageBox.Show("Unable to set label for attribute " + att);
					}
				}
			}

		}

		#endregion

		#region Position / Sequence

		private void PositionTextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			int num = 0;
			if (int.TryParse(PositionTextBox.Text, out num))
			{
				SetButtonSequence(_sourceElement, num);
			}
			else
			{
				PositionTextBox.Text = _sourceElement.AttributeValue("Sequence");
			}
		}

		private void MoveLeft_Click(object sender, RoutedEventArgs e)
		{
			int currentSeq = int.Parse(_sourceElement.Attribute("Sequence").Value);
			List<int> otherSeq = new List<int>();
			foreach (XElement siblings in _sourceElement.Parent.Elements())
			{
				otherSeq.Add(int.Parse(siblings.Attribute("Sequence").Value));
			}
			otherSeq.Sort();

			//already at left
			if (otherSeq[0] == currentSeq)
			{
				return;
			}

			//moving to leftmost position
			if (otherSeq[1] == currentSeq)
			{
				SetButtonSequence(_sourceElement, otherSeq[0] - 10);
				return;
			}

			//moving between the button to the left and the button two to the left
			for (int i = 0; i < otherSeq.Count; i++)
			{
				if (otherSeq[i] == currentSeq)
				{
					int mid = (otherSeq[i - 1] + otherSeq[i - 2]) / 2;
					SetButtonSequence(_sourceElement, mid);
					return;
				}
			}
		}

		private void MoveRight_Click(object sender, RoutedEventArgs e)
		{
			int currentSeq = int.Parse(_sourceElement.Attribute("Sequence").Value);
			List<int> otherSeq = new List<int>();
			foreach (XElement siblings in _sourceElement.Parent.Elements())
			{
				otherSeq.Add(int.Parse(siblings.Attribute("Sequence").Value));
			}
			otherSeq.Sort();
			otherSeq.Reverse();

			//already at left
			if (otherSeq[0] == currentSeq)
			{
				return;
			}

			//moving to leftmost position
			if (otherSeq[1] == currentSeq)
			{
				SetButtonSequence(_sourceElement, otherSeq[0] + 10);
				return;
			}

			//moving between the button to the left and the button two to the left
			for (int i = 0; i < otherSeq.Count; i++)
			{
				if (otherSeq[i] == currentSeq)
				{
					int mid = (otherSeq[i - 1] + otherSeq[i - 2]) / 2;
					SetButtonSequence(_sourceElement, mid);
					return;
				}
			}
		}

		private void SetButtonSequence(XElement button, int newSequence)
		{
			if (newSequence < 0)
			{
				newSequence = 0;
			}

			string oldNum = button.AttributeValue("Sequence");
			if (newSequence.ToString() != oldNum)
			{
				_sourceElement.SetAttributeValue("Sequence", newSequence.ToString());
				GetDiffGroup().SetAttributeValue("Sequence", newSequence.ToString());

				//re-render current ribbon tab
				MainWindow.CurrentMainPage.RenderRibbon();
				this.PositionTextBox.Text = newSequence.ToString();
			}
		}

		#endregion

		#region Images


		private void Image32TextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			UpdateImage(Image32TextBox, "Image32by32Popup");
		}

		private void UpdateImage(AutoCompleteBox imageBox, string attributeName)
		{
			string old = _sourceElement.AttributeValue(attributeName);
			if (string.Compare(old, imageBox.Text, StringComparison.CurrentCulture) != 0)
			{
				_sourceElement.SetAttributeValue(attributeName, imageBox.Text);
				GetDiffGroup().SetAttributeValue(attributeName, imageBox.Text);
				MainWindow.CurrentMainPage.RenderRibbon();
			}
		}

		#endregion


		//forwards an enter key press to a lostfocus event handler
		private void SetupEnterKeyHandler( Control c, Action<object,RoutedEventArgs> method )
		{
			c.KeyUp += (sender, e) =>
			{
				if (e.Key == Key.Enter)
				{
					method(c, e);
				}
			};
		}

		private XElement GetDiffGroup()
		{
			string id = _sourceElement.Attribute("Id").Value;
			XElement CustomActions = MainWindow.CurrentSolution.RibbonDiffXml.Descendants("CustomActions").First();
			XElement Button = CustomActions.Descendants("Group").Where(x => x.Attribute("Id").Value == id).FirstOrDefault();
			return Button;
		}

		private void ShowSectionsLinkButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			MainWindow.CurrentMainPage.ToggleSectionLines((TextBlock)sender);
		}

		private void ShowSectionsLinkButton_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Enter)
			{
				MainWindow.CurrentMainPage.ToggleSectionLines((TextBlock)sender);
			}
		}

		private void LanguageId_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (e.RemovedItems.Count > 0 && _isEditable)
			{
				string previousLang = ((ComboBoxItem)e.RemovedItems[0]).Tag.ToString();
				SaveLabel(LabelTextBox, new string[] { "Title" }, previousLang);
				SaveLabel(TooltipTextBox, new string[] { "Description" }, previousLang);
				Connection.CurrentConnection.LastLanguageUsed = GetSelectedLanguage();
			}
			LoadLabel(this._sourceElement, "Title", LabelTextBox);
			LoadLabel(this._sourceElement, "Description", TooltipTextBox);
		}

		private void BrowseForImage32_Click(object sender, RoutedEventArgs e)
		{
			BrowseForImage(Image32TextBox, "Image32by32Popup");
		}

		private void BrowseForImage(AutoCompleteBox acBox, string elementName)
		{
			string text = acBox.Text;
			if (String.IsNullOrWhiteSpace(text)) text = String.Empty;
			WebResourceDialog webResourceDialog = new WebResourceDialog(ResourceType.Image, text.Replace("$webresource:", ""));
			MainWindow.CurrentMainPage.ShowPopupDialog(webResourceDialog, (result) =>
			{
				if (result != null)
				{
					acBox.Text = "$webresource:" + result.ToString();
					UpdateImage(acBox, elementName);
				}
			});
		}
	}
}